#include "CentralCache.h"
#include "PageCache.h"
#include <assert.h>
// CentralCache.cpp
CentralCache CentralCache::_sInt;  
span* getonespan(Spanlist& list, size_t size)
{
	span* it = list.Begin();
	while (it != list.End())
	{
		if (it->_freelist != nullptr)
		{
			return it;
		}
		else
		{
			it = it->_next;
		}
	}


	//走到这里说明centralcache内没有空闲的span，此时要向pagecache内去申请新的span
	span* getspan = PageCache::getinstance()->newspan(Sizeclass::getNumFrompage(size));
	getspan->_objectsize = size;   //存在有便于内存的释放和回收，合并
	getspan->_isUse = true;


   //计算span的起始地址和页的总字节数
	char* start = (char*)(getspan->_pageid << PAGE_SHIFT);
	size_t ssize = getspan->_pagenum << PAGE_SHIFT;
	char* end = start + ssize;


	//把在PageCache中的申请大块span，切成小块并连接起来
	getspan->_freelist = start;
	start += size;  //将起始地址移动到下一块的起始地址
	void* tail = getspan->_freelist;
	while (start < end)
	{
		nextobj(tail) = start;
		tail = nextobj(tail);
		start += size;
	}
	list.pushfront(getspan);



  
}


size_t CentralCache::FetchtoThread(void*& start, void*& end, size_t batchNum, size_t size)
{
	size_t index = Sizeclass::getindex(size);
	
	//找到一个span并判断span是否为空
	span* Span = getonespan(CentralCache::_spanlist[index], size);
	assert(Span);
	assert(Span->_freelist);

	start = Span->_freelist;
	end = start;
	size_t i = 0;
	size_t actnum =	1;
	while (i < batchNum - 1 && nextobj(end) != nullptr)
	{
		end = nextobj(end);
		i++;
		actnum++;
	}
	Span->_freelist = nextobj(end);
	nextobj(end) = nullptr;

	return actnum;
}

void CentralCache::RealseListTospan(void* start, size_t size)
{

	  size_t index = Sizeclass::getindex(size);
	  while(start)
	  {
		  span* span = PageCache::getinstance()->mapobjecttospan(start); //获取小块内存所属的span的地址
		  void* next = nextobj(start);
		  nextobj(start) = span->_freelist;
		  span->_freelist = start;
		  start = next;
		  span->_usenumber--;
         

		  //说明此时centralcache有空闲的span,释放到pagecache中
		  if (span->_usenumber == 0)
		  {
			  _spanlist[index].erase(span);
			  span->_prev = nullptr;
			  span->_next = nullptr;



			  PageCache::getinstance()->RealsespantoPage(span);
		  }
		  start = next;

	  }
}
